#include "vcd-webkit.h"
#include "vcd-common-api/vcd-log.h"
#include "vcd-common-api/vcd-download.h"
#include "vcd-message-dialog.h"
#include "vcd-common-api/vcd-json-parser.h"
#include "vcd-common-api/vcd-conf/vcd-conf.h"
#include "vcd-rdp/vcd-rdp.h"
#include "vcd-start-window.h"
#include "vcd-setting-window/vcd-setting-window.h"
#ifdef HAVE_WEBKIT2GTK
#include <webkit2/webkit2.h>
#endif

typedef struct {
    char* host;
    char* token;
    char* refresh_token;
    char* user_data;
    GtkWidget* web_window;
    gpointer priv;
}vcd_webkit_ctx;

static int vcd_webkit_run_browser(vcd_webkit_ctx* ctx);

static void vcd_webkit_closed() {
    #ifdef __linux__
    char cmd[50] = {0};
    sprintf(cmd, "killall %s", VERYSTREAM_BIN);
    system(cmd);
    M_DEBUG(cmd);
    #endif
}

void wait_pid_exit(int sig){
    //LOG_ERROR("waitpidexit sig:%d",sig);
    switch (sig)
    {
        case SIGINT:
        break;
#ifdef __linux__
        case SIGCHLD:
        while(waitpid(-1, NULL, WNOHANG) > 0){
            //M_DEBUG("waitpidexit success\n");
        }
        break;
#endif
    }
}

static int vcd_webkit_run_vclient(const char* url) {
    #ifdef __linux__
    pid_t pid = fork();
    if (pid == 0) {

        const char* exe = "/usr/bin/spicy";

        if (execl(exe, "/f", url, NULL) < 0) {
            M_DEBUG("run vclient error");
        }
        exit(0);
    }
    signal(SIGCHLD, wait_pid_exit);
    #endif
    return 0;
}

static gboolean network_response_callback_old(gpointer response){

    struct network_response* res = (struct network_response*)response;

    vcd_api_login_data *vald = NULL;
    vald = (vcd_api_login_data *)calloc(1, sizeof(vcd_api_login_data));
    char *memory = res->memory;
    if (!response || !memory) {
        LOG_ERROR(" 连接失败（请检查网络或节点）！ ");
        vald->fail_msg = strdup(" 连接失败（请检查网络或节点）！ ");
        goto fail;
    }

    if (res->error_msg != NULL) {
        LOG_ERROR("登录失败: %s", res->error_msg);
        vald->fail_msg = strdup(res->error_msg);
        goto fail;
    }

    if (!vcd_json_parser_api_user_login(memory, vald))
        goto fail;

    if (vald->code && vald->token) {
        vcd_webkit_ctx* ctx = res->data_priv;
        ctx->token = strdup(vald->token);
        if (vald->refresh_token)
            ctx->refresh_token = strdup(vald->refresh_token);
        else
            ctx->refresh_token = NULL;
        if (vald->user_data)
            ctx->user_data = strdup((vald->user_data));
        else
            ctx->user_data = NULL;
        M_DEBUG("login sucess");
        #ifdef HAVE_WEBKIT2GTK
        vcd_webkit_run_browser(ctx);
        #endif
    }
    network_response_free(&res);
    return FALSE;

 fail:
    {
        char* msg = "登录失败!";
        if(vald && vald->fail_msg)
            msg = vald->fail_msg;

        message_box(msg);
        stop_login_button_state();
        network_response_free(&res);
    }
    return FALSE;
}

static gboolean network_response_callback(gpointer response){

    struct network_response* res = (struct network_response*)response;

    vcd_api_login_data *vald = NULL;
    vald = (vcd_api_login_data *)calloc(1, sizeof(vcd_api_login_data));

    char *memory = res->memory;
    if (!response || !memory) {
        LOG_ERROR(" 连接失败（请检查网络或节点）！ ");
        vald->fail_msg = strdup(" 连接失败（请检查网络或节点）！ ");
        goto fail;
    }

    if (res->error_msg != NULL) {
        LOG_ERROR("登录失败: %s", res->error_msg);
        vald->fail_msg = strdup(res->error_msg);
        goto fail;
    }

    if (!vcd_json_parser_api_user_login(memory, vald)) {

        struct vcd_conf* tmp_vcd_conf = g_vcd_conf;
        struct network_request_arg *req = NULL;
        if (strcmp(vald->fail_msg, "not json, try old api") == 0) {
            req = (struct network_request_arg *)calloc(1, sizeof(struct network_request_arg));
            if (req == NULL) {
                LOG_ERROR("malloc network_req_arg error");
                return -1;
            }
            snprintf(req->post_fields, sizeof(req->post_fields), "username=%s&password=%s", tmp_vcd_conf->username, tmp_vcd_conf->plaintext_passwd);
            snprintf(req->url, sizeof(req->url), "https://%s/api/user/login", tmp_vcd_conf->ip);
            req->timeout = 10L;
            req->http_method = CURLOPT_POST;
            req->data_priv = res->data_priv;
            req->callback = network_response_callback_old;
            M_DEBUG("begin user login");
            net_req_list_add(req);
            return FALSE;
        } else {
            goto fail;
        }
        //此处应该是要打开的，为了兼容以前的版本，此处如果失败的话有可能是接口使用错误，
        //所以此处再去申请一下老版本的接口平台完全更新之后即可删除
    }
    if (vald->code && vald->token) {
        vcd_webkit_ctx* ctx = res->data_priv;
        ctx->web_window = NULL;
        ctx->token = strdup(vald->token);
        if (vald->refresh_token)
            ctx->refresh_token = strdup(vald->refresh_token);
        else
            ctx->refresh_token = NULL;
        if (vald->user_data)
            ctx->user_data = strdup((vald->user_data));
        else
            ctx->user_data = NULL;
        M_DEBUG("login sucess");
        #ifdef HAVE_WEBKIT2GTK
        vcd_webkit_run_browser(ctx);
        #endif
    }

    network_response_free(&res);
    return FALSE;

 fail:
    {
        char* msg = "登录失败!";
        if(vald && vald->fail_msg)
            msg = vald->fail_msg;

        message_box(msg);
        stop_login_button_state();
        network_response_free(&res);
    }
    return FALSE;
}

int vcd_webkit_login(const char* portal_token, const char* host, const char* user, const char* pass, gpointer priv){

    vcd_webkit_ctx* ctx = (vcd_webkit_ctx*)calloc(1, sizeof(vcd_webkit_ctx));
    ctx->host = strdup(host);
    ctx->priv = priv;

    struct curl_slist *list = NULL;

    struct network_request_arg *req = (struct network_request_arg *)calloc(1, sizeof(struct network_request_arg));
    if (req == NULL) {
        LOG_ERROR("malloc network_req_arg error");
        return -1;
    }

    list = curl_slist_append(list, portal_token);
    list = curl_slist_append(list, "content-type:application/x-www-form-urlencoded");
    char x_client_ip[100] = {0};
    snprintf(x_client_ip, 100, "x-client-ip:%s", host);
    M_DEBUG(x_client_ip);
    list = curl_slist_append(list, x_client_ip);

    snprintf(req->post_fields, sizeof(req->post_fields), "username=%s&password=%s", user, pass);

    snprintf(req->url, sizeof(req->url), "https://%s/API/user/login", host);//NEW API

    req->timeout = 5L;
    req->http_method = CURLOPT_POST;
    req->list = list;
    req->data_priv = ctx;
    req->callback = network_response_callback;

    M_DEBUG("begin user login");

    net_req_list_add(req);

    return 0;
}

#ifdef HAVE_WEBKIT2GTK
static void _close(WebKitWebView *web_view) {
    M_DEBUG("_close");
    vcd_webkit_closed();
}

static void _web_process_terminated(WebKitWebView *web_view,WebKitWebProcessTerminationReason reason){
    M_DEBUG("_web_process_terminated reason:%d", reason);
    vcd_webkit_closed();
}

static gboolean _context_menu(WebKitWebView *web_view, WebKitContextMenu *context_menu,
                              GdkEvent *event, WebKitHitTestResult *hit_test_result, gpointer priv) {

    struct start_window* startWindow = (struct start_window*)priv;
    return !startWindow->open_develop_tool;
}

static void _resource_load_started(WebKitWebView *web_view,WebKitWebResource *resource,
                                   WebKitURIRequest *request, gpointer priv) {

    // https://vdp.verycloud.cn/api/user/logout
    // Vclient://xxxx

    const char* url_logout = "/api/user/logout";
    const char* url_logout_portal = "/API/user/logout";
    const char* url_vclient = "vclient://";

    const char* p = webkit_uri_request_get_uri(request);
    if (g_strrstr(p, url_logout) || g_strrstr(p, url_logout_portal)) {
        M_DEBUG("user logout");
        //not work
        webkit_web_view_try_close(web_view);

        // clear cache
        WebKitWebContext* context = webkit_web_view_get_context(WEBKIT_WEB_VIEW(web_view));
        webkit_web_context_clear_cache(context);
        if (priv) {
            gtk_widget_destroy((GtkWidget*)priv);
            priv = NULL;
        }

        if (!gtk_toggle_button_get_active((GtkToggleButton *)g_start_window->remember_passwd)) {
            gtk_entry_set_text((GtkEntry *)g_start_window->entry_passwd, "");
        } else {
            if (gtk_entry_get_visibility(GTK_ENTRY(g_start_window->entry_passwd)))
                set_passwd_entry_eye(g_start_window->entry_passwd, FALSE);
            if (g_icon_press_state != 0) {
                g_signal_handler_disconnect(g_start_window->entry_passwd, g_icon_press_state);
                g_icon_press_state = 0;
            }
        }

    } else if (g_strrstr(p, url_vclient)) {
        M_DEBUG("call Vclient protocol");
        vcd_webkit_run_vclient(p);
    } else {

    }
    //M_DEBUG("resource_load_started: %s",p);
    return;
}

void add_cookie_callback(WebKitCookieManager *cookie_manager, GAsyncResult *res, gpointer priv)
{
    GError *err = NULL;
    gboolean ret = webkit_cookie_manager_add_cookie_finish(cookie_manager, res, &err);
    if (err != NULL) {
        M_DEBUG("err msg:%s\n", err->message);
        return;
    }
    if (ret) {
        g_async_result_get_source_object(res);
    }

}

void get_cookie_callback(WebKitCookieManager *cookie_manager, GAsyncResult *res, gpointer priv)
{
    GList *l;
    GError *err = NULL;
    GList *list = webkit_cookie_manager_get_cookies_finish(cookie_manager, res, &err);
    if (err != NULL) {
        M_DEBUG("err msg:%s\n", err->message);
        return;
    }

    if (list) {
        for (l=list; l != NULL; l=l->next) {

            gpointer one = l->data;
            SoupCookie *co = (SoupCookie *)one;
            M_DEBUG("%s", co->name);
        }
    }
}

void _load_changed(WebKitWebView *web_view, WebKitLoadEvent load_event, gpointer priv){

     vcd_webkit_ctx *ctx = (vcd_webkit_ctx *)priv;

     if (load_event == WEBKIT_LOAD_STARTED) {

         stop_login_button_state();

         if (ctx->web_window != NULL)
            gtk_widget_show_all(ctx->web_window);
     }
/*
     if (load_event == WEBKIT_LOAD_FINISHED) {
        char* host = ctx->host;
        char* token = ctx->token;
        char* user_data = ctx->user_data;

        // set cookit
        WebKitWebContext* context = webkit_web_view_get_context(WEBKIT_WEB_VIEW(web_view));
        WebKitCookieManager* cookie = webkit_web_context_get_cookie_manager(context);

        webkit_web_context_clear_cache(context);
        //webkit_web_context_set_cache_model(context,WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
        //webkit_web_context_set_disk_cache_directory(context, "/tmp/cache");

        SoupCookie soupCookit = {0};
        soupCookit.name = "token";
        soupCookit.path = "/";
        soupCookit.value = token;
        soupCookit.domain = host;
        webkit_cookie_manager_add_cookie(cookie, &soupCookit, NULL, add_cookie_callback, NULL);

        SoupCookie webviewCookit = {0};
        webviewCookit.name = "x-webview";
        webviewCookit.path = "/";
        webviewCookit.value = "1";
        webviewCookit.domain = host;
        webkit_cookie_manager_add_cookie(cookie, &webviewCookit, NULL, add_cookie_callback, NULL);

        SoupCookie userCookit = {0};
        userCookit.name = "user";
        userCookit.path = "/";
        userCookit.value = user_data;
        userCookit.domain = host;
        webkit_cookie_manager_add_cookie(cookie, &userCookit, NULL, add_cookie_callback, NULL);

        //webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_IGNORE);

        char url[500] = {0};
        snprintf(url, sizeof(url), "https://%s", host);
        webkit_cookie_manager_get_cookies(cookie, url, NULL, get_cookie_callback, NULL);
     }
*/
}

static gboolean _load_failed(WebKitWebView *web_view, WebKitLoadEvent load_event,
                             const gchar *failing_uri, GError *error, gpointer priv) {

    M_DEBUG("failing_uri:%s, error:%s", failing_uri, error->message);
    const char* url_vclient = "vclient://";
    if (g_strrstr(failing_uri, url_vclient))
        return TRUE;
    stop_login_button_state();
    webkit_web_view_try_close(web_view);
    if (priv) {
        gtk_widget_destroy((GtkWidget*)priv);
        priv = NULL;
    }
    //message_box(error->message);
    return TRUE;
}

//static gboolean _load_failed_tls(WebKitWebView *web_view, gchar *host, GTlsCertificate *certificate, GTlsCertificateFlags errors, gpointer priv){

    // WebKitWebContext* context = webkit_web_view_get_context(WEBKIT_WEB_VIEW(web_view));
    // if (certificate != NULL)
    //printf("_load_failed_tls host=%s", host);
    // webkit_web_context_allow_tls_certificate_for_host(context, certificate, host);
    // webkit_web_view_reload(web_view);
    //return FALSE;//FALSE直接跳转到_load_failed
//}

//load vnc
static void _web_view_show(WebKitWebView *web_view)
{
    GtkWidget *win = gtk_widget_get_toplevel((WebKitWebView *)web_view);
    gtk_widget_show_all(win);
    return;
}

//load vnc
static GtkWidget* _create_web_view(WebKitWebView *web_view, WebKitNavigationAction *action, gpointer priv)
{
    GtkWidget *window_ch = NULL;
    GtkWidget *webview_new = NULL;
    GtkWidget* scrolled = NULL;
    GtkWidget* window_pa = (GtkWidget*)priv;

    window_ch = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    GdkScreen *screen = gdk_screen_get_default();
    int w = gdk_screen_get_width(screen);
    int h = gdk_screen_get_height(screen);
    gtk_window_set_default_size(GTK_WINDOW(window_ch), w, h);

    scrolled = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

    webview_new = webkit_web_view_new_with_related_view(web_view);

    gtk_window_set_keep_above(GTK_WINDOW(window_ch), TRUE);
    gtk_window_set_modal(GTK_WINDOW(window_ch), TRUE);
    gtk_window_set_transient_for(GTK_WINDOW(window_ch), GTK_WINDOW(window_pa));
    gtk_window_set_title(GTK_WINDOW(window_ch), "vnc");

    g_signal_connect(WEBKIT_WEB_VIEW(webview_new), "ready-to-show", G_CALLBACK(_web_view_show), NULL);

    gtk_container_add(GTK_CONTAINER(scrolled), (GtkWidget *)webview_new);
    gtk_container_add(GTK_CONTAINER(window_ch), scrolled);

    return webview_new;
}

static int vcd_webkit_run_browser(vcd_webkit_ctx* ctx){

    GtkWidget* webview  = NULL;
    GtkWidget* scrolled = NULL;
    GtkWidget* window = NULL;

    struct start_window* startWindow = (struct start_window*)ctx->priv;

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    webview = webkit_web_view_new();
    scrolled = gtk_scrolled_window_new(NULL, NULL);

    GdkScreen *screen = gdk_screen_get_default();
    int w = gdk_screen_get_width(screen);
    int h = gdk_screen_get_height(screen);

    gtk_window_set_default_size(GTK_WINDOW(window), w, h);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

    gtk_container_add(GTK_CONTAINER(scrolled), webview);
    gtk_container_add(GTK_CONTAINER(window), scrolled);

    WebKitSettings *webkitSettings = webkit_settings_new();
    webkit_settings_set_enable_fullscreen(webkitSettings, TRUE);
    webkit_settings_set_enable_javascript(webkitSettings, TRUE);
    webkit_settings_set_enable_webgl(webkitSettings, TRUE);
    webkit_settings_set_enable_plugins(webkitSettings, TRUE);
    webkit_settings_set_enable_developer_extras(webkitSettings, TRUE);
    webkit_settings_set_enable_page_cache(webkitSettings, TRUE);
    webkit_settings_set_enable_accelerated_2d_canvas(webkitSettings, TRUE);
    webkit_settings_set_enable_offline_web_application_cache(webkitSettings, FALSE);
    webkit_settings_set_enable_html5_local_storage(webkitSettings, TRUE);
    webkit_settings_set_enable_java(webkitSettings, TRUE);

    webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webview), webkitSettings);

    ctx->web_window = window;

    g_signal_connect(WEBKIT_WEB_VIEW(webview), "resource_load_started", G_CALLBACK(_resource_load_started), window);
    g_signal_connect(WEBKIT_WEB_VIEW(webview), "context_menu", G_CALLBACK(_context_menu), ctx->priv);
    g_signal_connect(WEBKIT_WEB_VIEW(webview), "load_failed", G_CALLBACK(_load_failed), NULL);
    g_signal_connect(WEBKIT_WEB_VIEW(webview), "web_process_terminated", G_CALLBACK(_web_process_terminated), NULL);
    g_signal_connect(WEBKIT_WEB_VIEW(webview), "close", G_CALLBACK(_close), NULL);
    g_signal_connect(WEBKIT_WEB_VIEW(webview), "load_changed", G_CALLBACK(_load_changed), ctx);
    g_signal_connect(WEBKIT_WEB_VIEW(webview), "create", G_CALLBACK(_create_web_view), window);
    char tmp[500] = {0};
    char* host = ctx->host;
    char* refresh_token = ctx->refresh_token;
    char* token = ctx->token;
    char* user_data = ctx->user_data;

    if (!ctx->refresh_token)
        snprintf(tmp, sizeof(tmp), "https://%s/", host);
    else
        snprintf(tmp, sizeof(tmp), "https://%s/switch/user?refresh=%s&x-webview=1", host, refresh_token);

    const char* url = tmp;
    M_DEBUG("load url:%s\n", url);
    //const char* url = "http://www.baidu.com";
    //const char* url = "https://vdp.verycloud.cn";
    //const char* url = "https://goss.cfp.cn/cms/image/image/52a474bfcdb2432685bc3886a69291d9.gif";
    //const char* url = "file:///root/workspace/openVclient.html";

    // set cookit
    WebKitWebContext* context = webkit_web_view_get_context(WEBKIT_WEB_VIEW(webview));
    WebKitCookieManager* cookie = webkit_web_context_get_cookie_manager(context);

    webkit_web_context_clear_cache(context);

    SoupCookie soupCookit = {0};
    soupCookit.name = "token";
    soupCookit.path = "/";
    soupCookit.value = token;
    soupCookit.domain = host;
    webkit_cookie_manager_add_cookie(cookie, &soupCookit, NULL, NULL, NULL);

    SoupCookie webviewCookit = {0};
    webviewCookit.name = "x-webview";
    webviewCookit.path = "/";
    webviewCookit.value = "1";
    webviewCookit.domain = host;
    webkit_cookie_manager_add_cookie(cookie, &webviewCookit, NULL, NULL, NULL);

    SoupCookie userCookit = {0};
    userCookit.name = "user";
    userCookit.path = "/";
    userCookit.value = user_data;
    userCookit.domain = host;
    webkit_cookie_manager_add_cookie(cookie, &userCookit, NULL, NULL, NULL);

    webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
    webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), url);

    if (startWindow->full_screen)
         gtk_window_fullscreen(GTK_WINDOW(window));
    return 0;
}
#endif
